package logger;

import java.util.Calendar;

public class Logger {
	
	
	public static	 boolean	isLogging			= true;
	public static	 boolean	printLineNum		= true;
	public static 	 boolean	printCallerMethod	= true;
	public static	 boolean	printCallerClass	= true;
	public static	 boolean	printCallerFile		= true;
	public static	 boolean	printDate			= true;
	public static	 boolean	printTime			= true;
	public static	 boolean	printTabs			= true;
	public static	 boolean	printText			= true;
	//
	// Internal variables
	//
	private	static	int		lineNumFieldSize	= 5;
	private static	int		callerFieldSize		= 30;
	private static	int		callerFileFieldSize = 20;
	private static	int		depth				= 1;
	
	private static	int				lastDepth = 0;
	private static	int				numTabs = 0;

	private static	final String	blank = " ";
	private static boolean	firstStdout		= true;
	private static boolean	firstStderr		= true;

	private static	final void	addTab()	{	numTabs++;							}
	private static	final void	delTab()	{	numTabs = Math.max(0, numTabs-1);	}
	
	private	static	final String	fstring(String S, int size, boolean isLeftJustify, String pad) {
		String output = "";
		if (S==null) {
			return output = blankString(size);
		} else {
			int L = S.length();
			if (isLeftJustify) {
				if (L >= size) {
					output = S.substring(0,size);
				} else {
					output = S + blankString(size-L,pad);
				}
			} else {
				if (L >= size) {
					output = S.substring(L-size);
				} else {
					output = blankString(size-L,pad) + S;
				}
			}
		}
		return output;
	}
	private	static	final String	tabString(int numTabs) {
		return blankString(numTabs*2);
	}
	private static	final String	blankString(int numBlanks) {	return blankString(numBlanks, blank);	}
	private static	final String	blankString(int numBlanks, String B) {
		String output = "";
		for(int i=0; i<numBlanks; i++) {
			output += B;
		}
		return output;
	}
	private	static	final String	simplifyClassName(String S) {
		if (S==null) 			return "";
		if (S.contains("."))	return S.substring(S.indexOf(".")+1);
		return S;
	}
	private	static	final String	simplifyFileName(String S) {
		if (S==null) 			return "";
		if (S.contains("//"))	return S.substring(S.indexOf("//")+1);
		return S;
	}

	private static	final String	getHeader() {
		Throwable			T = new Throwable();
		StackTraceElement	S[] = T.getStackTrace();
		String				header = "";
		Calendar			C = Calendar.getInstance();

		if (lastDepth > S.length) {
			delTab();
		} else if (lastDepth < S.length) {
			addTab();
		}
		lastDepth = S.length;
		
		if (S.length>depth) {
			if (printDate)			header += dateString(C) + " ";
			if (printTime)			header += timeString(C) + " ";
			if (printCallerFile)	header += fstring(simplifyFileName(S[depth+1].getFileName()), callerFileFieldSize, true, blank) + ": "; 
			if (printLineNum)		header += "Line[" + fstring(Integer.toString(S[depth+1].getLineNumber()), lineNumFieldSize, false, blank) + "] ";

			if (printCallerClass || printCallerMethod) {
				String caller = "";
				if (printCallerClass)						caller += simplifyClassName(S[depth+1].getClassName());
				if (printCallerClass && printCallerMethod)	caller += ".";
				if (printCallerMethod)						caller += simplifyClassName(S[depth+1].getMethodName());
				header += fstring(caller, callerFieldSize, true, blank);
				header += ": ";
			}
		}

		if (printTabs)	header += tabString(numTabs);
		return header;
	}
	private static	final String	getText(Object O) {
		if (O==null)				return "null";
		if (O instanceof String)	return (String) O;
		return O.toString();
	}

	private static	final void toStdout(String T, String H) {
		if (T.length()>0) {
			if (firstStdout) {
				firstStdout = false;
				T = "\n" + T;
			}
			T = T.replaceAll("\n", "\n" + H);
			
			System.out.print(T);
		}
	}
	private static	final void toStderr(String T, String H) {
		if (T.length()>0) {
			if (firstStderr) {
				firstStderr = false;
				T = "\n" + T;
			}
			T = T.replaceAll("\n", "\n" + H);
			
			System.err.print(T);
		}
	}

	public static	final void println(Object S) {
		if (isLogging) {
			String	H = getHeader();
			String	T = getText(S);
			toStdout(T + "\n", H);
		}
	}
	public static	final void errorln(Object S) {
		if (isLogging) {
			String H = getHeader();
			String	T = getText(S);
			toStderr(T + "\n", H);
		}
	}
	public static	final void print(Object S) {
		if (isLogging) {
			String H = getHeader();
			String	T = getText(S);
			toStdout(T, H);
		}
	}
	public static	final void perror(Object S) {
		if (isLogging) {
			String H = getHeader();
			String	T = getText(S);
			toStderr(T, H);
		}
	}
	
	public static	final void printStackTrack() {
		Throwable T = new Throwable();
		T.printStackTrace(System.err);
	}
	
	public static	final String quote(String S) {	
		return quote(S,"\"", "\"");	
	}
	private static	final String quote(String S, String preTag, String postTag) {
		return "\"" + S + "\"";
	}

	private static final String dateString(Calendar C) {
		String	output = "";
		String	dayNum		= fstring(	Long.toString(C.get(Calendar.DAY_OF_MONTH)),	2, false, "0");
		String	yearNum		= fstring(	Long.toString(C.get(Calendar.YEAR)), 			4, false, " ");
		String	dayOfWeek	= dayStr[C.get(Calendar.DAY_OF_WEEK)-1];
		String	monthOfYear	= monthStr[C.get(Calendar.MONTH)];
		
		output = dayOfWeek + " " + monthOfYear + "," + dayNum + "," + yearNum;
		return output;
	}
	
	private static	final String timeString(Calendar C) {
		String	output = "";
		String	hour	= fstring(	Long.toString(C.get(Calendar.HOUR_OF_DAY)),		2, false, "0");
		String	minute	= fstring(	Long.toString(C.get(Calendar.MINUTE)),			2, false, "0");
		String	second	= fstring(	Long.toString(C.get(Calendar.SECOND)),			2, false, "0");
		String	ms		= fstring(	Long.toString(C.get(Calendar.MILLISECOND)),		3, false, "0");
		String	part	= partOfDay[C.get(Calendar.AM_PM)];
		
		output = hour + ":" + minute + ":" + second + ":" + second + ":" + ms + " " + part;
		return output;
	}

	private static final String dayStr[]	= {	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"	};
	private static final String	monthStr[]	= {	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Uni"	};
	private static final String partOfDay[]	= { "am", "pm" };
}



